package com.school.sports.config;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.nio.charset.Charset;
import java.time.Duration;

/**
 * Redis配置类
 * 配置RedisTemplate、缓存管理器和序列化策略
 */
@Configuration
@EnableCaching  // 启用缓存注解
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // 设置key序列化方式string
        template.setKeySerializer(new StringRedisSerializer());
        // 设置value的序列化方式json，使用GenericJackson2JsonRedisSerializer替代默认序列化
        template.setValueSerializer(new RedisSerializer<Object>() {
            private final Charset charset = Charset.forName("UTF-8");

            @Override
            public byte[] serialize(Object o) throws SerializationException {
                if (o == null) {
                    return new byte[0];
                }
                return JSON.toJSONString(o, JSONWriter.Feature.WriteClassName).getBytes(charset);
            }

            @Override
            public Object deserialize(byte[] bytes) throws SerializationException {
                if (bytes == null || bytes.length <= 0) {
                    return null;
                }
                String str = new String(bytes, charset);
                return JSON.parseObject(str, Object.class);
            }
        });

        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new RedisSerializer<Object>() {
            private final Charset charset = Charset.forName("UTF-8");

            @Override
            public byte[] serialize(Object o) throws SerializationException {
                if (o == null) {
                    return new byte[0];
                }
                return JSON.toJSONString(o, JSONWriter.Feature.WriteClassName).getBytes(charset);
            }

            @Override
            public Object deserialize(byte[] bytes) throws SerializationException {
                if (bytes == null || bytes.length <= 0) {
                    return null;
                }
                String str = new String(bytes, charset);
                return JSON.parseObject(str, Object.class);
            }
        });

        template.afterPropertiesSet();
        return template;
    }

    /**
     * 配置缓存管理器
     * @param connectionFactory Redis连接工厂
     * @return 缓存管理器
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        // 配置序列化（解决乱码问题）
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(30)) // 设置缓存有效期30分钟
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer())) // 设置key的序列化规则
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer())) // 设置value的序列化规则
                .disableCachingNullValues(); // 不缓存空值

        // 设置一个初始化的缓存空间set集合
        RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .transactionAware() // 支持事务
                .build();

        return cacheManager;
    }

    /**
     * 配置key序列化
     * @return key序列化器
     */
    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

    /**
     * 配置value序列化
     * @return value序列化器
     */
    private RedisSerializer<Object> valueSerializer() {
        return new RedisSerializer<Object>() {
            private final Charset charset = Charset.forName("UTF-8");

            @Override
            public byte[] serialize(Object o) throws SerializationException {
                if (o == null) {
                    return new byte[0];
                }
                return JSON.toJSONString(o, JSONWriter.Feature.WriteClassName).getBytes(charset);
            }

            @Override
            public Object deserialize(byte[] bytes) throws SerializationException {
                if (bytes == null || bytes.length <= 0) {
                    return null;
                }
                String str = new String(bytes, charset);
                return JSON.parseObject(str, Object.class);
            }
        };
    }
}